<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> 联合类型&类型保护 </title>
</head>
<body>
    
</body>
</html>
<script>
    //年初四 
    //人与人之间最大的鸿沟 就是我们看待事物的角度和立场的不同 
    /*
        庄子和穗子出去玩 走到一座桥上 庄子和穗子说 你看河水里的鱼那么清闲 这就是鱼的快乐 
    穗子说 你又不是鱼 怎么知道鱼时快乐的 庄子说 你又不是我 怎么知道我不知道鱼的快乐讷 穗
    子说 我不是你 当然不知道你 你也不是鱼 也当然不知道鱼的快乐 这是肯定的 
    */
    
    //注意 只有联合类型存在的情况下 才需要类型保护  
    //     普通的类型注释 并不需要我们这种特殊操作  

//联合类型 即可以认定应该变量可能有两种&两种以上的类型 
    //demo 代码如下  (声明两个接口)
    /*声明两个接口Waiter(服务员)接口和Teacher(技师)接口，然后在写一个judgeWho(判断是谁)的方法，里边传入一个animal(任意值)，
    这时候可以能是Waiter,也可能是Teacher。所以我们使用了联合类型，关键符号是|(竖线)。*/
    interface Waiter {
        anjiao: boolean;
        say: () => {};
    }
    interface Teacher {
        anjiao: boolean;
        skill: () => {};
    }
    function judgeWho(animal: Waiter | Teacher) {}    
    //至此 即什么是联合类型 

    function judgeWho(animal: Waiter | Teacher) {
        animal.say();
    }
    //坑 如果直接写一个方法 就会报错 因为judgeWho不能准确判断联合类型 具体实例是什么 (即不知道谁家的谁)
    //这时候抛出概念即 类型保护 类型保护有多种方法 下面常见的  
    
 
//类型保护 类型断言 
    //类型断言 通过断言的方式确定传递过来的准确值   (类型断言 用来手动指定一个值的类型)    
    /*注意上面代码
        会anjiao 说明是技师  这时候通过断言 animal as Teacher 然后直接调用skill方法 程序不报错
        不会anjiao 说明不是    这时候调用say() 方法不报错   
        !通过类型断言方式进行类型保护 常见的保护形式  
    */
    interface Waiter {
    anjiao: boolean;
    say: () => {};
    }

    interface Teacher {
    anjiao: boolean;
    skill: () => {};
    }

    function judgeWho(animal: Waiter | Teacher) {
    if (animal.anjiao) {
        (animal as Teacher).skill();
    }else{
        (animal as Waiter).say();
    }
    }


//类型保护 -in语法  
    //还经常用in语法来作 类型保护 比如用if来判断animal里有没有skill()方法  //续上面的俩接口
    function judgeWho2(animal: Waiter | Teacher) {
    if ("skill" in animal) {
        animal.skill();
    } else {
        animal.say();
    }
    }
    //这里的else部分能够自动判断 得益于ts的自动判断  (即让程序自动去判断里有没有是谁的 然后抛出)


//类型保护 -typeof语法 
    //写一个新的add方法 接收两个参数 两个参数是数字&字符串 
    //如果不做任何的类型保护 只相加 就报错 
    function add(first:number|string,secoed:number|string){
        return first +second;
    }
    //解决这个问题 直接使用typeof来解决讷
    function add(first: string | number, second: string | number) {
    if (typeof first === "string" || typeof second === "string") {
        return `${first}${second}`;
    }
    return first + second;
    }


//类型保护 instanceof语法 
    //demo是 类型保护一个对象 这时候用instanceof语法了 代码如下 
    class Numberobj{
        count: number;
    }
    //写一个addObj方法 传递参数 为任意值的object 也可以是Numberobj的实例 
    //然后我们返回相加值 不进行类型保护 代码是报错的 
    function addObj(first:object|Numberobj,second:object|Numberobj){
        return first.count + second.count
    }
    //报错 不要紧 直接使用 instanceof语法判断一下 就可以解决问题 
    function addObj(first: object | NumberObj, second: object | NumberObj) {
    if (first instanceof NumberObj && second instanceof NumberObj) {
        return first.count + second.count;
    }
    return 0;
    }
    //注意 instanceof只能用在类上  还有其他不常用的方法 
    


    //类型断言 
        //类型断言 用来手动指定一个值的类型 
        //<类型>值  或  值as类型 
        //在jsx语法中(React的jsx语法ts版) 必须采用后面一种 避免冲突 
        //注意 类型断言不是类型转换 断言成一个联合类型中不存在的类型是不准许的  //会报错 
        let num:number|string = "10"
        num = 20;
        console.log(num.length) // 报错 因为联合类型 访问必须是共有的属性 number没有长度的  
        //遇到这样的问题 就考虑类型断言了  
        function getAssert(name:string|number){
                //                                  //都是指明那么属性为string 
                //return  (<string>name).length     //方法1 
                return(name as string).length       //方法2
        }
    
    




















    









































</script>